package com.szp.drug.config;

import com.szp.drug.util.DrugConstant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Spring Security配置类
 * @author SuZePing
 * @create 2021-02-20 15:51
 * @E-mail suzeping10@126.com
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)/* 启用全局方法权限控制，prePostEnabled = true 表示开启一些注解的使用 */
@EnableWebSecurity/* 启用web环境下权限控制功能 */
public class WebApplicationSecurityConfig extends WebSecurityConfigurerAdapter {
	// 修改DelegatingFilterProxy的源码
	// 使SpringMVC[dispatcherServlet]把WebApplicationSecurityConfig扫描到IOC容器
	// 才可以针对浏览器请求进行权限控制
	// 而并非是Spring[contextLoaderListener]扫描WebApplicationSecurityConfig

	@Autowired
	private UserDetailsService userDetailsService;

	@Autowired
	private BCryptPasswordEncoder passwordEncoder;

	/**
	 * 拦截服务器请求
	 * @param security
	 * @throws Exception
	 */
	@Override
	protected void configure(HttpSecurity security) throws Exception {
		security.authorizeRequests()// 对请求进行授权
				.antMatchers("/admin/to/login/page.html")// 首页
				.permitAll()// 无条件访问
				.antMatchers("/static/**")// 静态资源
				.permitAll()// 无条件访问
				.antMatchers("/admin/get/page.html")
				.access("hasRole('用户管理员') or hasRole('超级管理员')")
				.antMatchers("/role/get/page.html")
				.access("hasRole('角色管理员') or hasRole('超级管理员')")
				.antMatchers("/medicine/get/tree.html")
				.access("hasRole('药品管理员') or hasRole('超级管理员')")
				.antMatchers("/instrument/get/tree.html")
				.access("hasRole('器械管理员') or hasRole('超级管理员')")
				.antMatchers("/sell/get/tree.html")
				.access("hasRole('店员') or hasRole('超级管理员')")
				.antMatchers("/check/get/tree.html")
				.access("hasRole('医师') or hasRole('超级管理员')")
				.anyRequest()// 任意请求
				.authenticated()// 认证后访问
				.and()
				.exceptionHandling()
				.accessDeniedHandler(new AccessDeniedHandler() {
					@Override
					public void handle(HttpServletRequest request, HttpServletResponse response,
									   AccessDeniedException accessDeniedException) throws IOException, ServletException {
						request.setAttribute("exception", new Exception(DrugConstant.MESSAGE_ACCESS_DENIED));
						request.getRequestDispatcher("/WEB-INF/views/system-error.jsp").forward(request, response);
					}
				})
				.and()
				.csrf()
				.disable()// 禁用csrf
				.formLogin()// 表单登录
				.loginPage("/admin/to/login/page.html")// 指定登陆页面
				.loginProcessingUrl("/security/do/login.html")// 指定处理登录的地址
				.defaultSuccessUrl("/admin/to/main/page.html",true)// 指定登陆成功去往的地址
				.usernameParameter("account")// 账号的请求参数name
				.passwordParameter("password")// 密码的请求参数name
				.and()
				.logout()
				.logoutUrl("/security/do/logout.html")// 指定处理注销的地址
				.logoutSuccessUrl("/admin/to/login/page.html");// 注销成功去往的页面
	}

	/**
	 * 登陆验证
	 * @param auth
	 * @throws Exception
	 */
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(userDetailsService)
				.passwordEncoder(passwordEncoder);// 密码加盐
	}

}
